/*NOTICE

This software was produced for the U. S. Government
under Contract No. FA8721-09-C-0002, and is
subject to the Rights in Noncommercial Computer Software
and Noncommercial Computer Software Documentation Clause
(DFARS) 252.227-7014 (JUN 1995)

(c) 2009 The MITRE Corporation. All Rights Reserved.
*/
package org.mitre.xmltransform.spmiftouml2;

import java.io.File;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import org.mitre.xmltransform.XmlOutputDocument;
import org.mitre.xmltransform.transform.Transform;
import org.w3c.dom.Element;

public class SpmifToUml2Transform extends Transform {

	@Override
	public void initialize(File pInputFile, File pOutputFile) {
		mInput = new SpmifInputDocument(pInputFile);
		mOutput = new XmlOutputDocument(pOutputFile);

		mNextId = 1;
		mStereotypes = new HashMap<String,StereotypeInfo>();
	}
	
	@Override
	public void transform() {
		if (generateOutput()) {
			mOutput.finishDocument();
			mOutput.writeOutput();
		}		
	}

	private boolean generateOutput() {
		try {			
			mRootElement = mOutput.addRootElement("XMI", null);
			mRootElement.setAttribute("xmi.version", "1.2");
/*			Attr schemaAttrib = mOutput.createAttributeNS("http://www.w3.org/2000/xmlns/", "UML");
			schemaAttrib.setPrefix("xmlns");
			schemaAttrib.setValue("org.omg.xmi.namespace.UML");
			mRootElement.setAttributeNodeNS(schemaAttrib);

			schemaAttrib = mOutput.createAttributeNS("http://www.w3.org/2000/xmlns/", "UML2");
			schemaAttrib.setPrefix("xmlns");
			schemaAttrib.setValue("org.omg.xmi.namespace.UML2");
			mRootElement.setAttributeNodeNS(schemaAttrib);
*/			
			DateFormat df = DateFormat.getDateTimeInstance();
			SimpleDateFormat sdf = (SimpleDateFormat)df;
			sdf.applyPattern("EEE MMM dd HH:mm:ss zzz yyyy");
			mRootElement.setAttribute("timestamp", sdf.format(new Date()));
			
			Element xmiHeader = mOutput.addElement(mRootElement, "XMI.header", null);
			Element xmiDoc = mOutput.addElement(xmiHeader, "XMI.documentation", null);
			mOutput.addElement(xmiDoc, "XMI.exporter", "org.mitre.xmltransform.spmiftouml2.SpmifToUml2Transform");
			mOutput.addElement(xmiDoc, "XMI.exporterVersion", "1.0");
			mOutput.addElement(xmiDoc, "XMI.metaModelVersion", "1.4.4");
			Element xmiContent = mOutput.addElement(mRootElement, "XMI.content", null);
			generateModel(xmiContent);
			generateDefaultClassDiagram(xmiContent);
			return true;
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}
	
	private void generateDefaultClassDiagram(Element  pParentElement) {
		mOutput.addXmlSnippet(pParentElement, "<UML:Diagram xmlns:UML=\"org.omg.xmi.namespace.UML\" name=\"Class Diagram_1\" isVisible=\"true\" zoom=\"1.0\" xmi.id=\"Diagram Class Diagram_1\">" +
      "<UML:GraphElement.position>" +
        "<XMI.field>0.0</XMI.field>" +
        "<XMI.field>0.0</XMI.field>" +
      "</UML:GraphElement.position>" +
      "<UML:GraphNode.size>" +
        "<XMI.field>0.0</XMI.field>" +
        "<XMI.field>0.0</XMI.field>" +
      "</UML:GraphNode.size>" +
      "<UML:Diagram.viewport>" +
        "<XMI.field>0.0</XMI.field>" +
        "<XMI.field>0.0</XMI.field>" +
      "</UML:Diagram.viewport>" +
      "<UML:GraphElement.semanticModel>" +
        "<UML:SimpleSemanticModelElement typeInfo=\"ClassDiagram\" presentation=\"\" xmi.id=\"SimpleSemanticModelElement 1\"></UML:SimpleSemanticModelElement>" +
      "</UML:GraphElement.semanticModel>" +
      "<UML:GraphElement.contained>" +
        "<UML:GraphNode isVisible=\"true\" xmi.id=\"GraphNode 1\">" +
          "<UML:GraphElement.position>" +
            "<XMI.field>19.0</XMI.field>" +
            "<XMI.field>0.0</XMI.field>" +
          "</UML:GraphElement.position>" +
          "<UML:GraphNode.size>" +
            "<XMI.field>118.9199</XMI.field>" +
            "<XMI.field>21.0</XMI.field>" +
          "</UML:GraphNode.size>" +
          "<UML:GraphElement.semanticModel>" +
            "<UML:SimpleSemanticModelElement typeInfo=\"NameCompartment\" presentation=\"\" xmi.id=\"SimpleSemanticModelElement 2\"></UML:SimpleSemanticModelElement>" +
          "</UML:GraphElement.semanticModel>" +
          "<UML:GraphElement.contained>" +
            "<UML:GraphNode isVisible=\"true\" xmi.id=\"GraphNode 2\">" +
              "<UML:GraphElement.position>" +
                "<XMI.field>5.0</XMI.field>" +
                "<XMI.field>3.0</XMI.field>" +
              "</UML:GraphElement.position>" +
              "<UML:GraphNode.size>" +
                "<XMI.field>19.5562</XMI.field>" +
                "<XMI.field>15.0</XMI.field>" +
              "</UML:GraphNode.size>" +
              "<UML:GraphElement.semanticModel>" +
                "<UML:SimpleSemanticModelElement typeInfo=\"DiagramNamePrefix\" presentation=\"\" xmi.id=\"SimpleSemanticModelElement 3\"></UML:SimpleSemanticModelElement>" +
              "</UML:GraphElement.semanticModel>" +
            "</UML:GraphNode>" +
            "<UML:GraphNode isVisible=\"true\" xmi.id=\"GraphNode 3\">" +
              "<UML:GraphElement.position>" +
                "<XMI.field>24.5562</XMI.field>" +
                "<XMI.field>3.0</XMI.field>" +
              "</UML:GraphElement.position>" +
              "<UML:GraphNode.size>" +
                "<XMI.field>84.3638</XMI.field>" +
                "<XMI.field>15.0</XMI.field>" +
              "</UML:GraphNode.size>" +
              "<UML:GraphElement.semanticModel>" +
                "<UML:SimpleSemanticModelElement typeInfo=\"Name\" presentation=\"\" xmi.id=\"SimpleSemanticModelElement 4\"></UML:SimpleSemanticModelElement>" +
              "</UML:GraphElement.semanticModel>" +
            "</UML:GraphNode>" +
          "</UML:GraphElement.contained>" +
        "</UML:GraphNode>" +
      "</UML:GraphElement.contained>" +
      "<UML:Diagram.owner>" +
        "<UML:Uml1SemanticModelBridge presentation=\"\" xmi.id=\"Uml1SemanticModelBridge 1\">" +
          "<UML:Uml1SemanticModelBridge.element>" +
            "<UML:Model xmi.idref=\"Model model 1\"></UML:Model>" +
          "</UML:Uml1SemanticModelBridge.element>" +
        "</UML:Uml1SemanticModelBridge>" +
      "</UML:Diagram.owner>" +
    "</UML:Diagram>");
		
	}
	
	private void generateModel(Element pParentElement) {
/*	    <UML:Model xmi.id = 'I3497894m10cea7ecd17mm7e77' name = 'model 3' isSpecification = 'false'
	        isRoot = 'false' isLeaf = 'false' isAbstract = 'false'>
	        <UML:Namespace.ownedElement>
	*/
		Element modelElement = mOutput.addElement(pParentElement, "org.omg.xmi.namespace.UML", "Model", null);
		Element namespaceOwnedElement = mOutput.addElement(modelElement, "org.omg.xmi.namespace.UML", "Namespace.ownedElement", null);
		// generate packages of types if necessary?
		generateCollaboration(namespaceOwnedElement);
	}
	
	private void generateCollaboration(Element pParentElement) {
/*
 * <UML:Collaboration xmi.id = 'I3497894m10cea7ecd17mm7ae4' name = 'Collaboration_1'
          visibility = 'public' isSpecification = 'false' isRoot = 'false' isLeaf = 'false'
          isAbstract = 'false'>
          <UML:ModelElement.stereotype>
            <UML:Stereotype xmi.idref = 'Im59b06f5cm10d57b0d217mm76c3'/>
          </UML:ModelElement.stereotype>
          <UML2:BehavioredClassifier.ownedBehavior>
 */
		Element collaboration = mOutput.addElement(pParentElement, "org.omg.xmi.namespace.UML", "Collaboration", null);
		String id = generateXmiId();
		collaboration.setAttribute("xmi.id", id);
		collaboration.setAttribute("name", "Collaboration_" + id);
		collaboration.setAttribute("visibility", "public");
		collaboration.setAttribute("isSpecification", "false");
		collaboration.setAttribute("isRoot", "false");
		collaboration.setAttribute("isLeaf", "false");
		collaboration.setAttribute("isAbstract", "false");
		Element modelElementStereotype = mOutput.addElement(collaboration, "org.omg.xmi.namespace.UML", "ModelElement.stereotype", null);
		Element stereotypeRef = mOutput.addElement(modelElementStereotype, "org.omg.xmi.namespace.UML", "Stereotype", null);
		stereotypeRef.setAttribute("xmi.idref", addStereotype("PAcontext", "Collaboration"));
		Element ownedBehavior = mOutput.addElement(collaboration, "org.omg.xmi.namespace.UML2", "BehavioredClassifier.ownedBehavior", null);
		generateInteraction(ownedBehavior);
		
		generateStereotypes(pParentElement);
	}
	
	private void generateStereotypes(Element pParentElement) {
	}
	
	private void generateInteraction(Element pParentElement) {
/*
 *             <UML2:Interaction xmi.id = 'I3497894m10cea7ecd17mm7ae3' name = 'Interaction_1'
              visibility = 'public' isSpecification = 'false' isRoot = 'false' isLeaf = 'false'
              isAbstract = 'false' isActive = 'false'>
              <UML:Classifier.feature>
                <UML:Attribute xmi.id = 'I3497894m10cea7ecd17mm7aca' name = 'attribute_1'
                  visibility = 'private' isSpecification = 'false' ownerScope = 'instance'
                  changeability = 'changeable'>
                  <UML2:TypedElement.type>
                    <UML:Class xmi.idref = 'I3497894m10cea7ecd17mm7e6d'/>
                  </UML2:TypedElement.type>
                </UML:Attribute>

 */
		Element interaction = mOutput.addElement(pParentElement, "org.omg.xmi.namespace.UML2", "Interaction", null);
		String id = generateXmiId();
		interaction.setAttribute("xmi.id", id);
		interaction.setAttribute("name", "Interaction_" + id);
		interaction.setAttribute("visibility", "public");
		interaction.setAttribute("isSpecification", "false");
		interaction.setAttribute("isRoot", "false");
		interaction.setAttribute("isLeaf", "false");
		interaction.setAttribute("isAbstract", "false");
		interaction.setAttribute("isActive", "false");
		
		Element classifierFeature = mOutput.addElement(interaction, "org.omg.xmi.namespace.UML", "Classifier.feature", null);
		generateInteractionAttributes(classifierFeature);
		
		Element structuredClassifier = mOutput.addElement(interaction, "org.omg.xmi.namespace.UML2", "StructuredClassifier.ownedConnector", null);
		generateInteractionConnectors(structuredClassifier);
		
		Element interactionFragments = mOutput.addElement(interaction, "org.omg.xmi.namespace.UML2", "Interaction.fragment", null);
		generateInteractionFragments(interactionFragments);

		Element interactionMessages = mOutput.addElement(interaction, "org.omg.xmi.namespace.UML2", "Interaction.message", null);
		generateInteractionMessages(interactionMessages);

		Element interactionLifelines = mOutput.addElement(interaction, "org.omg.xmi.namespace.UML2", "Interaction.lifeline", null);
		generateInteractionLifelines(interactionLifelines);
	}
	
	private void generateInteractionLifelines(Element pParentElement) {
	}
	private void generateInteractionMessages(Element pParentElement) {
	}
	private void generateInteractionFragments(Element pParentElement) {
	}
	private void generateInteractionAttributes(Element pParentElement) {	
	}
	private void generateInteractionConnectors(Element pParentElement) {
	}
	
	class StereotypeInfo {
		public StereotypeInfo(String pId, String pName, String pBase) {
			mId = pId;
			//mName = pName;
			//mBase = pBase;
		}
		
		public String getId() {
			return mId;
		}
		
		private String mId;
		//private String mBase;
		//private String mName;
	}
	
	private String addStereotype(String pName, String pBase) {
		String id;
		StereotypeInfo si;
		if (mStereotypes.containsKey(pName)) {
			si = (StereotypeInfo)mStereotypes.get(pName);
			id = si.getId();
		} else {
			id = generateXmiId();
			mStereotypes.put(pName, new StereotypeInfo(id, pName, pBase));
		}
		return id;
	}
	
	private String generateXmiId() {
		String result = Long.toString(mNextId);
		mNextId++;
		return result;
	}
	
	private Map<String,StereotypeInfo> mStereotypes;
	private long mNextId;
	private SpmifInputDocument mInput;
	private XmlOutputDocument mOutput;
	private Element mRootElement;
}
